package research.ui.views;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.part.ViewPart;

import research.entity.Entity;
import research.entity.EntityFactory;
import research.entity.EntityType;
import research.model.BaseHierarchy;
import research.model.EntityContentProvider;
import research.persistence.PersistenceManager;
import research.ui.editors.EditorFactory;
import research.ui.views.comparators.EntityComparator;
import research.ui.views.comparators.EntityNameComparator;
import research.ui.views.filters.EntityNameFilter;

public abstract class HierarchyView extends ViewPart {

	protected TreeViewer viewer;
	private BaseHierarchy hierarchy;
	private Text nameFilter;
	private Composite filterArea;
	private Composite sorterArea;
	private Button sortDirection;
	
	public HierarchyView(BaseHierarchy hierarchy) {
		super();
		this.hierarchy = hierarchy;
	}
	
	protected void renderViewer(Composite parent) {
		GridLayout la = new GridLayout(1, false);
		parent.setLayout(la);
		la.horizontalSpacing = 0;
		la.verticalSpacing = 0;
		la.marginHeight = 0;
		la.marginWidth = 0;

		GridData gd = new GridData(GridData.FILL_BOTH);
		viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
		viewer.setContentProvider(new EntityContentProvider(hierarchy));
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.setComparator(getComparator());
		viewer.getControl().setLayoutData(gd);
	}
	
	protected ViewerComparator getComparator() {
		return new EntityNameComparator();
	}
	
	protected void loadData() {
		viewer.setInput(PersistenceManager.getInstance());
	}
	
	protected void renderAdd(Composite parent) {
		FormToolkit toolkit = new FormToolkit(parent.getDisplay());

		Section section = toolkit.createSection(parent, Section.TITLE_BAR | Section.TWISTIE);
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		section.setLayoutData(gd);
		section.setText("Создать...");
		Composite addArea = toolkit.createComposite(section);
		addArea.setLayout(new GridLayout(1, false));
		section.setClient(addArea);
		
		for (EntityType type : hierarchy.getTypes()) {
			gd = new GridData();
			Hyperlink link = toolkit.createHyperlink(addArea, type.getName(), SWT.NONE);
			link.setLayoutData(gd);
			link.addHyperlinkListener(new AddHyperlinkListener(type));
		}
		
	}
	
	protected void renderFilter(Composite parent) {
		FormToolkit toolkit = new FormToolkit(parent.getDisplay());

		Section section = toolkit.createSection(parent, Section.TITLE_BAR | Section.TWISTIE);
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		section.setLayoutData(gd);
		section.setText("Фильтрация");
		filterArea = toolkit.createComposite(section);
		filterArea.setLayout(new GridLayout(1, false));
		section.setClient(filterArea);
		
		section = toolkit.createSection(filterArea, Section.EXPANDED
				| Section.TITLE_BAR | Section.TWISTIE);
		gd = new GridData(GridData.FILL_HORIZONTAL);
		section.setLayoutData(gd);
		section.setText("По имени");
		Composite composite = toolkit.createComposite(section);
		composite.setLayout(new GridLayout(1, false));
		section.setClient(composite);
		
		gd = new GridData(GridData.FILL_HORIZONTAL);
		nameFilter = toolkit.createText(composite, "",
				SWT.BORDER);
		nameFilter.setLayoutData(gd);
		
		renderAdditionalFilters(filterArea);
		

		gd = new GridData();
		Button btn = new Button(filterArea, SWT.NONE);
		btn.setText("Применить");
		btn.setLayoutData(gd);
		btn.addSelectionListener(new BtnSelectionListener());
	}
	
	protected void renderSorter(Composite parent) {
		FormToolkit toolkit = new FormToolkit(parent.getDisplay());

		Section section = toolkit.createSection(parent, Section.TITLE_BAR | Section.TWISTIE);
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		section.setLayoutData(gd);
		section.setText("Сортировка");
		sorterArea = toolkit.createComposite(section);
		sorterArea.setLayout(new GridLayout(1, false));
		section.setClient(sorterArea);
		
		gd = new GridData();
		Button sortName = new Button(sorterArea, SWT.NONE);
		sortName.setText("По имени");
		sortName.setLayoutData(gd);
		sortName.addSelectionListener(new SortBtnSelectionListener(new EntityNameComparator()));
		
		renderAdditionalSorters(sorterArea);
		
		gd = new GridData();
		sortDirection = new Button(sorterArea, SWT.CHECK);
		sortDirection.setText("по убыванию");
		sortDirection.setLayoutData(gd);
	}
	
	private void updateFilter() {
		List<ViewerFilter> filters = new ArrayList<ViewerFilter>();
		if (!nameFilter.getText().isEmpty())
			filters.add(new EntityNameFilter(nameFilter.getText(), hierarchy.getRootType()));
		
		addAdditionalFilters(filters);
		
		ViewerFilter[] arr = {};
		
		viewer.setFilters(filters.toArray(arr));
	}
	
	private void updateSorter(EntityComparator comp) {
		comp.setDesc(sortDirection.getSelection());
		viewer.setComparator(null);
		viewer.setComparator(comp);
	}
	
	protected void addAdditionalFilters(List<ViewerFilter> filters) {
	}

	protected void renderAdditionalFilters(Composite filterArea) {
	}
	
	protected void renderAdditionalSorters(Composite filterArea) {
	}

	class BtnSelectionListener implements SelectionListener {
		public void widgetDefaultSelected(SelectionEvent e) {
		}

		public void widgetSelected(SelectionEvent e) {
			updateFilter();
		}
	}
	
	class SortBtnSelectionListener implements SelectionListener {
		private EntityComparator comp;
		
		public SortBtnSelectionListener(EntityComparator comp) {
			super();
			this.comp = comp;
		}

		public void widgetDefaultSelected(SelectionEvent e) {
		}

		public void widgetSelected(SelectionEvent e) {
			updateSorter(comp);
		}
	}

	@Override
	public void createPartControl(Composite parent) {
		renderViewer(parent);
		renderAdd(parent);
		renderFilter(parent);
		renderSorter(parent);
		loadData();
		
		hookDoubleClickAction();

		getSite().setSelectionProvider(viewer);
	}
	
	private void hookDoubleClickAction() {
		viewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(
					org.eclipse.jface.viewers.DoubleClickEvent event) {
				editSelected((StructuredSelection)event.getSelection());
			};
		});
	}

	private void editSelected(StructuredSelection sel) {
		Object obj = sel.getFirstElement();
		if (obj instanceof Entity) {
			Entity entity = (Entity) obj;
			EditorFactory.openEditor(entity);
		}
	}

	@Override
	public void setFocus() {
		viewer.getControl().setFocus();
	}
	
	public class AddHyperlinkListener implements IHyperlinkListener {
		private EntityType type;
		
		public AddHyperlinkListener(EntityType type) {
			super();
			this.type = type;
		}

		@Override
		public void linkActivated(HyperlinkEvent e) {
			Entity parent = (Entity)((StructuredSelection) viewer.getSelection()).getFirstElement();
			EntityFactory.openNew(type, parent);
		}

		@Override
		public void linkEntered(HyperlinkEvent e) {
		}

		@Override
		public void linkExited(HyperlinkEvent e) {
		}
	}

}